using System;
using System.Collections.Generic;
using System.Dynamic;
using Newtonsoft.Json;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Expression.SPI;
using T.ServiceComponent.Cache.Service;
using T.FAS.Runtime.Expression.Entity;

namespace T.FAS.Runtime.Expression.Plugin
{
    public class CacheExecutor : DynamicObject, IDynamicActionAdapter
    {
        private static CacheService cacheService = null;
        CacheExecutor()
        {
            try
            {
                cacheService = CacheService.GetInstance("DefaultPool");
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_1360889252", "获取DefaultPool失败,Msg:{0}", e)}");
            }
        }

        /// <summary>
        /// JS脚本动态调用Dynamic必备函数
        /// 脚本写法：ConfigCenter.();
        /// </summary>
        /// <param name = "name">动态调用DynamicObject中的函数名称</param>
        /// <param name = "args">参数信息，参数类型必须增加 params</param>
        /// <returns></returns>
        public dynamic DynamicInvoke(string name, params object[] args)
        {
            return ExecuteCache(name, args);
        }

        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out dynamic result)
        {
            result = DynamicInvoke(binder.Name, args);
            return true;
        }

        /// <summary>
        /// 执行获取配置中心值的逻辑
        /// </summary>
        /// <param name = "funcName"></param>
        /// <param name = "paramList"></param>
        /// <returns></returns>
        private dynamic ExecuteCache(string funcName, object[] paramList)
        {
            switch (funcName)
            {
                case "HashBatchSet":
                    if (paramList.Length == 4)
                    {
                        string hashId = Convert.ToString(paramList[0]);
                        Dictionary<string, object> keyValueDic = JsonConvert.DeserializeObject<Dictionary<string, object>>(JsonConvert.SerializeObject(paramList[1]));
                        string poolName = Convert.ToString(paramList[2]);
                        DateTime expiresAt = Convert.ToDateTime(paramList[3]);
                        return HashBatchSet(hashId, keyValueDic, poolName, expiresAt);
                    }
                    else
                    {
                        throw new Exception($"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Expression_72088020", "HashBatchSet参数个数不匹配")}");
                    }

                default:
                    break;
            }

            throw new FasException(ExprExceptionCode.ErrorExpr, "Unsupported Cache." + funcName);
        }

#region Private Funcs
        public object Get(string key)
        {
            try
            {
                if (string.IsNullOrEmpty(key))
                    return null;
                using (ICacheClient client = cacheService.GetClient())
                {
                    return client.Get<object>(key);
                }
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_1746677911", "获取Redis{0}失败：", key)}" + e.ToString());
            }
        }

        /// <summary>
        /// 批量设置哈希里的数据
        /// </summary>
        /// <typeparam name = "T"></typeparam>
        /// <param name = "hashId"></param>
        /// <param name = "keyValueDic"></param>
        /// <param name = "expiresIn"></param>
        /// <returns></returns>
        private bool HashBatchSet(string hashId, Dictionary<string, object> keyValueDic, string poolName, DateTime expiresAt)
        {
            if (string.IsNullOrEmpty(hashId))
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Expression_772774557", "hashId不能为空")}");
            }

            if (keyValueDic == null || keyValueDic.Keys.Count == 0)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Expression_917409529", "keyValueDic不能为空")}");
            }

            foreach (KeyValuePair<string, object> item in keyValueDic)
            {
                if (item.Value == null)
                {
                    throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_1648493240", "hash缓存中{0}的值不能设置为null", item.Key)}");
                }
            }

            try
            {
                var poolService = CacheService.GetInstance(poolName);
                using (ICacheClient client = poolService.GetClient())
                {
                    using (ICachePipeline pipeline = client.CreatePipeline())
                    {
                        foreach (KeyValuePair<string, object> item in keyValueDic)
                        {
                            pipeline.QueueCommand((ICacheClient p) => p.SetEntryInHash<object>(hashId, item.Key, item.Value));
                        }
                        pipeline.QueueCommand((ICacheClient p) => p.ExpireEntryAt(hashId, expiresAt));
                        pipeline.Flush();
                    }
                }

                return true;
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_1659719215", "设置Redis{0}失败：{1}", hashId, e)}");
            }
        }

        public object Get(string key, string poolName)
        {
            try
            {
                if (string.IsNullOrEmpty(key))
                    return null;
                var poolService = CacheService.GetInstance(poolName);
                using (ICacheClient client = poolService.GetClient())
                {
                    return client.Get<object>(key);
                }
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_413026185", "获取Redis{0}失败：{1}", key, e)}");
            }
        }

        public object GetValueFromHash(string hashId, string key)
        {
            try
            {
                if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key))
                    return null;
                using (ICacheClient client = cacheService.GetClient())
                {
                    return client.GetValueFromHash<object>(hashId, key);
                }
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_413026185", "获取Redis{0}失败：{1}", key, e)}");
            }
        }

        public long GetHashCount(string hashId, string poolName)
        {
            try
            {
                if (string.IsNullOrEmpty(hashId))
                    return 0;
                var poolService = CacheService.GetInstance(poolName);
                using (ICacheClient client = cacheService.GetClient())
                {
                    return client.GetHashCount(hashId);
                }
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_230151302", "获取HashCount{0}失败：{1}", hashId, e)}");
            }
        }

        public object SetEntryInHash(string hashId, string key, object value, string poolName)
        {
            try
            {
                if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key))
                    return null;
                var poolService = CacheService.GetInstance(poolName);
                using (ICacheClient client = poolService.GetClient())
                {
                    return client.SetEntryInHash<object>(hashId, key, value);
                }
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_1659719215", "设置Redis{0}失败：{1}", key, e)}");
            }
        }

        public object SetEntryInHash(string hashId, string key, object value)
        {
            try
            {
                if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key))
                    return null;
                using (ICacheClient client = cacheService.GetClient())
                {
                    return client.SetEntryInHash<object>(hashId, key, value);
                }
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_1659719215", "设置Redis{0}失败：{1}", key, e)}");
            }
        }

        public object GetValueFromHash(string hashId, string key, string poolName)
        {
            try
            {
                if (string.IsNullOrEmpty(hashId) || string.IsNullOrEmpty(key))
                    return null;
                var poolService = CacheService.GetInstance(poolName);
                using (ICacheClient client = poolService.GetClient())
                {
                    return client.GetValueFromHash<object>(hashId, key);
                }
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_413026185", "获取Redis{0}失败：{1}", key, e)}");
            }
        }

        public bool Set(string key, object value)
        {
            try
            {
                if (string.IsNullOrEmpty(key))
                    return false;
                using (ICacheClient client = cacheService.GetClient())
                {
                    return client.Set(key, value);
                }
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_1659719215", "设置Redis{0}失败：{1}", key, e)}");
            }
        }

        public bool Set(string key, object value, string poolName)
        {
            try
            {
                if (string.IsNullOrEmpty(key))
                    return false;
                var poolService = CacheService.GetInstance(poolName);
                using (ICacheClient client = poolService.GetClient())
                {
                    return client.Set(key, value);
                }
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_1659719215", "设置Redis{0}失败：{1}", key, e)}");
            }
        }

        public bool Set(string key, object value, string poolName, DateTime expiresAt)
        {
            try
            {
                if (string.IsNullOrEmpty(key))
                    return false;
                if (!string.IsNullOrEmpty(poolName))
                {
                    var poolService = CacheService.GetInstance(poolName);
                    using (ICacheClient client = poolService.GetClient())
                    {
                        return client.Set(key, value, expiresAt);
                    }
                }
                else
                {
                    using (ICacheClient client = cacheService.GetClient())
                    {
                        return client.Set(key, value, expiresAt);
                    }
                }
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_1659719215", "设置Redis{0}失败：{1}", key, e)}");
            }
        }
        public bool RemoveEntry(string hashId)
        {
            using (ICacheClient client = cacheService.GetClient())
            {
                return client.RemoveEntry(hashId);
            }
        }
        public bool Remove(string key)
        {
            if (string.IsNullOrEmpty(key))
                return false;
            try
            {
                using (ICacheClient client = cacheService.GetClient())
                {
                    return client.Remove(key);
                }
            }
            catch (Exception e)
            {
                throw;
            }
        }

        public bool Remove(string key, string poolName)
        {
            if (string.IsNullOrEmpty(key))
                return false;
            try
            {
                var poolService = CacheService.GetInstance(poolName);
                using (ICacheClient client = poolService.GetClient())
                {
                    return client.Remove(key);
                }
            }
            catch (Exception e)
            {
                throw new FasException(ExprExceptionCode.ErrorExpr, $"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_1033926846", "移除Redis{0}失败：{1}", key, e)}");
            }
        }
#endregion
    }
}